package com.min.nio.rpc.server;

import com.min.nio.module.Student;
import com.min.nio.rpc.util.MessageUtils;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Set;

/**
 * create by sirmin on 2018/3/19
 */
public class Server {

    private Selector selector;
    private ServerSocketChannel serverSocketChannel;
    public Server() {
        try {
            this.selector = Selector.open();
            serverSocketChannel = ServerSocketChannel.open();
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("获取selector失败");
        }
    }

    public Server bind(final int port) {
        try {
            serverSocketChannel.configureBlocking(false);
            serverSocketChannel.bind(new InetSocketAddress(port));
            serverSocketChannel.register(this.selector, SelectionKey.OP_ACCEPT);
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("打开连接失败");
        }
        return this;
    }

    public void doSelect() throws Exception {
        while (this.selector.select() > 0) {
            final Set<SelectionKey> selectionKeys = this.selector.selectedKeys();
            final Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while (iterator.hasNext()) {
                final SelectionKey selectionKey = iterator.next();
                if (selectionKey.isAcceptable()) {
                    doAccept();
                } else if (selectionKey.isReadable()) {
                    doRead(selectionKey);
                }
                iterator.remove();
            }
        }
    }

    private void doRead(SelectionKey selectionKey) throws Exception {
        final SocketChannel channel = (SocketChannel) selectionKey.channel();


        final ByteBuffer byteBuffer = ByteBuffer.allocate(1);
        channel.read(byteBuffer);
        byteBuffer.flip();
        final byte cl = byteBuffer.get();
        byteBuffer.clear();
        final ByteBuffer clazz = ByteBuffer.allocateDirect(cl);
        channel.read(clazz);
        clazz.flip();
        final CharsetDecoder charsetDecoder = StandardCharsets.UTF_8.newDecoder();
        final CharBuffer decode = charsetDecoder.decode(clazz);
        final String className = decode.toString();

        channel.read(byteBuffer);
        byteBuffer.flip();
        final byte ml = byteBuffer.get();
        byteBuffer.clear();
        final ByteBuffer method = ByteBuffer.allocateDirect(ml);
        channel.read(method);
        method.flip();
        final String methodName = charsetDecoder.decode(method).toString();

        final Object message = MessageUtils.getMessage(channel);

        final ByteArrayOutputStream out = new ByteArrayOutputStream();
        final ObjectOutputStream objectOutputStream = new ObjectOutputStream(out);
        final Object handler = Handler.handler(className, methodName, message);
        objectOutputStream.writeObject(handler);
        channel.write(ByteBuffer.wrap(out.toByteArray()));
        channel.close();
        System.out.println("关闭");

    }

    public void doAccept() throws Exception {
        final SocketChannel channel = serverSocketChannel.accept();
        channel.configureBlocking(false);
        channel.register(this.selector, SelectionKey.OP_READ);
    }


    public static void main(String[] args) throws Exception {
        new Server()
                .bind(8888)
                .doSelect();
    }
}
